home *** CD-ROM | disk | FTP | other *** search
/ Developer CD Series 1998 April: Mac OS SDK / Dev.CD Apr 98 SDK1.toast / Development Kits (Disc 1) / QuickDraw 3D / Samples / SampleCode / BoxMooV / sources / BoxPaint_Support.c < prev    next >
Encoding:
C/C++ Source or Header  |  1997-08-14  |  15.0 KB  |  548 lines  |  [TEXT/CWIE]

  1. /*  BoxPaint_Support.c
  2.                                                                             
  3.     Quickdraw 3D sample code
  4.     
  5.     This file contains utility routines for QuickDraw 3d sample code. This
  6.     app shows how to apply a texture shader to an object.  Bear in mind
  7.     that any object that you wish to texture map needs to have UV parameters
  8.     applied.
  9.                                                                             
  10.     Nick Thompson
  11.     (c)1994-96 Apple computer Inc., All Rights Reserved                                
  12.  
  13. */
  14.  
  15. /* --------------------------------------------------------------------
  16. ** Includes
  17. */
  18.  
  19. #include "BoxPaint_Support.h"
  20.  
  21. #include "QD3DDrawContext.h"
  22. #include "QD3DRenderer.h"
  23. #include "QD3DShader.h"
  24. #include "QD3DCamera.h"
  25. #include "QD3DLight.h"
  26. #include "QD3DGeometry.h"
  27. #include "QD3DGroup.h"
  28. #include "QD3DMath.h"
  29. #include "QD3DTransform.h"
  30.  
  31.  
  32. /* --------------------------------------------------------------------
  33. ** Global Variables
  34. */
  35. static     TQ3Point3D    documentGroupCenter;
  36. static    float        documentGroupScale;
  37.  
  38. /* --------------------------------------------------------------------
  39. ** Local Functions
  40. */
  41. void                    GetGroupBBox(DocumentPtr theDocument, TQ3BoundingBox *viewBBox) ;                                                
  42. static    TQ3Status        MyAddShaderToGroup( TQ3GroupObject group ) ;
  43. static    TQ3Status        GetDocumentGroupBoundingBox(DocumentPtr theDocument,
  44.                                                     TQ3BoundingBox *viewBBox);
  45. TQ3DrawContextObject    MyNewDrawContext(WindowPtr theWindow) ;
  46. TQ3CameraObject         MyNewCamera(WindowPtr theWindow) ;
  47. TQ3GroupObject            MyNewLights(void) ;
  48.  
  49.  
  50. /* ---------------------------------------------------------------------------------- */
  51. /*  attach a shader to the group */
  52.  
  53. static TQ3Status MyAddShaderToGroup( TQ3GroupObject group )
  54. {
  55. /*     TQ3ShaderObject    illuminationShader = Q3PhongIllumination_New();
  56. */    TQ3ShaderObject    illuminationShader = Q3LambertIllumination_New();
  57.  
  58.     Q3Group_AddObject(group, illuminationShader);
  59.     Q3Object_Dispose(illuminationShader);
  60.     return(kQ3Success);
  61. }
  62.  
  63. TQ3ViewObject MyNewView(WindowPtr theWindow)
  64. {
  65.     TQ3Status                myStatus;
  66.     TQ3ViewObject            myView;
  67.     TQ3DrawContextObject        myDrawContext;
  68.     TQ3RendererObject        myRenderer;
  69.     TQ3CameraObject            myCamera;
  70.     TQ3GroupObject            myLights;
  71.     
  72.     myView = Q3View_New();
  73.     
  74.     /*     Create and set draw context. */
  75.     if ((myDrawContext = MyNewDrawContext(theWindow)) == nil )
  76.         goto bail;
  77.         
  78.     if ((myStatus = Q3View_SetDrawContext(myView, myDrawContext)) == kQ3Failure )
  79.         goto bail;
  80.  
  81.     Q3Object_Dispose( myDrawContext ) ;
  82.     
  83.     /*     Create and set renderer. */
  84.     
  85.     
  86.     
  87.     /*  this would use the wireframe renderer */
  88.     /*    Not very useful for this app    */
  89. #if 0
  90.     myRenderer = Q3Renderer_NewFromType(kQ3RendererTypeWireFrame);
  91.     if ((myStatus = Q3View_SetRenderer(myView, myRenderer)) == kQ3Failure ) {
  92.         goto bail;
  93.     }
  94. #else
  95.     /*  this would use the interactive plug-in renderer */
  96.  
  97.     if ((myRenderer = Q3Renderer_NewFromType(kQ3RendererTypeInteractive)) != nil ) {
  98.         if ((myStatus = Q3View_SetRenderer(myView, myRenderer)) == kQ3Failure ) {
  99.             goto bail;
  100.         }
  101.     }
  102.     else {
  103.         goto bail;
  104.     }
  105. #endif
  106.  
  107.     Q3Object_Dispose( myRenderer ) ;
  108.     
  109.     /*     Create and set camera. */
  110.     if ( (myCamera = MyNewCamera(theWindow)) == nil )
  111.         goto bail;
  112.         
  113.     if ((myStatus = Q3View_SetCamera(myView, myCamera)) == kQ3Failure )
  114.         goto bail;
  115.  
  116.     Q3Object_Dispose( myCamera ) ;
  117.     
  118.     /*     Create and set lights. */
  119.     if ((myLights = MyNewLights()) == nil )
  120.         goto bail;
  121.         
  122.     if ((myStatus = Q3View_SetLightGroup(myView, myLights)) == kQ3Failure )
  123.         goto bail;
  124.         
  125.     Q3Object_Dispose(myLights);
  126.  
  127.     /*     Done!!! */
  128.     return ( myView );
  129.     
  130. bail:
  131.     /*     If any of the above failed, then don't return a view. */
  132.     return ( nil );
  133. }
  134.  
  135. /* ---------------------------------------------------------------------------------- */
  136.  
  137. TQ3DrawContextObject MyNewDrawContext(WindowPtr theWindow)
  138. {
  139.     TQ3DrawContextData        myDrawContextData;
  140.     TQ3MacDrawContextData    myMacDrawContextData;
  141.     TQ3ColorARGB            ClearColor;
  142.     TQ3DrawContextObject    myDrawContext ;
  143.     
  144.     /*     Set the background color. */
  145.     ClearColor.a = 1.0;
  146.     ClearColor.r = 1.0;
  147.     ClearColor.g = 1.0;
  148.     ClearColor.b = 1.0;
  149.     
  150.     /*     Fill in draw context data. */
  151.     myDrawContextData.clearImageMethod = kQ3ClearMethodWithColor;
  152.     myDrawContextData.clearImageColor = ClearColor;
  153.     myDrawContextData.paneState = kQ3False;
  154.     myDrawContextData.maskState = kQ3False;
  155.     myDrawContextData.doubleBufferState = kQ3True;
  156.  
  157.     myMacDrawContextData.drawContextData = myDrawContextData;
  158.     
  159.     myMacDrawContextData.window = (CGrafPtr) theWindow;        /*  this is the window associated with the view */
  160.     myMacDrawContextData.library = kQ3Mac2DLibraryNone;
  161.     myMacDrawContextData.viewPort = nil;
  162.     myMacDrawContextData.grafPort = nil;
  163.     
  164.     /*     Create draw context and return it, if it’s nil the caller must handle */
  165.     myDrawContext = Q3MacDrawContext_New(&myMacDrawContextData) ;
  166.  
  167.     return myDrawContext ;
  168. }
  169.  
  170. /* ---------------------------------------------------------------------------------- */
  171.  
  172. TQ3CameraObject MyNewCamera(WindowPtr theWindow)
  173. {
  174.     TQ3ViewAngleAspectCameraData    perspectiveData;
  175.     TQ3CameraObject                camera;
  176.     
  177.     TQ3Point3D                     from     = { 0.0, 0.0, 6.0 };
  178.     TQ3Point3D                     to         = { 0.0, 0.0, 0.0 };
  179.     TQ3Vector3D                 up         = { 0.0, 1.0, 0.0 };
  180.  
  181.     float                         fieldOfView = 1.0;
  182.     float                         hither         =  0.001;
  183.     float                         yon         =  1000;
  184.     
  185.     TQ3Status                    returnVal = kQ3Failure ;
  186.  
  187.  
  188.     perspectiveData.cameraData.placement.cameraLocation     = from;
  189.     perspectiveData.cameraData.placement.pointOfInterest     = to;
  190.     perspectiveData.cameraData.placement.upVector             = up;
  191.  
  192.     perspectiveData.cameraData.range.hither    = hither;
  193.     perspectiveData.cameraData.range.yon     = yon;
  194.  
  195.     perspectiveData.cameraData.viewPort.origin.x = -1.0;
  196.     perspectiveData.cameraData.viewPort.origin.y = 1.0;
  197.     perspectiveData.cameraData.viewPort.width = 2.0;
  198.     perspectiveData.cameraData.viewPort.height = 2.0;
  199.     
  200.     perspectiveData.fov                = fieldOfView;
  201.     perspectiveData.aspectRatioXToY    =
  202.         (float) (theWindow->portRect.right - theWindow->portRect.left) / 
  203.         (float) (theWindow->portRect.bottom - theWindow->portRect.top);
  204.         
  205.     camera = Q3ViewAngleAspectCamera_New(&perspectiveData);
  206.  
  207.     return camera ;
  208. }
  209.  
  210.  
  211. /* ---------------------------------------------------------------------------------- */
  212.  
  213. TQ3GroupObject MyNewLights()
  214. {
  215.     TQ3GroupPosition            myGroupPosition;
  216.     TQ3GroupObject            myLightList;
  217.     TQ3LightData                myLightData;
  218.     TQ3PointLightData        myPointLightData;
  219.     TQ3DirectionalLightData    myDirectionalLightData;
  220.     TQ3LightObject            myAmbientLight, myPointLight, myFillLight;
  221.     TQ3Point3D                pointLocation = { -10.0, 0.0, 10.0 };
  222.     TQ3Vector3D                fillDirection = { 10.0, 0.0, 10.0 };
  223.     TQ3ColorRGB                WhiteLight = { 1.0, 1.0, 1.0 };
  224.     
  225.     /*     Set up light data for ambient light.  This light data will be used for point and fill */
  226.     /*     light also. */
  227.  
  228.     myLightData.isOn = kQ3True;
  229.     myLightData.color = WhiteLight;
  230.     
  231.     /*     Create ambient light. */
  232.     myLightData.brightness = .2;
  233.     myAmbientLight = Q3AmbientLight_New(&myLightData);
  234.     if ( myAmbientLight == nil )
  235.         goto bail;
  236.     
  237.     /*     Create point light. */
  238.     myLightData.brightness = 1.0;
  239.     myPointLightData.lightData = myLightData;
  240.     myPointLightData.castsShadows = kQ3False;
  241.     myPointLightData.attenuation = kQ3AttenuationTypeNone;
  242.     myPointLightData.location = pointLocation;
  243.     myPointLight = Q3PointLight_New(&myPointLightData);
  244.     if ( myPointLight == nil )
  245.         goto bail;
  246.  
  247.     /*     Create fill light. */
  248.     myLightData.brightness = .2;
  249.     myDirectionalLightData.lightData = myLightData;
  250.     myDirectionalLightData.castsShadows = kQ3False;
  251.     myDirectionalLightData.direction = fillDirection;
  252.     myFillLight = Q3DirectionalLight_New(&myDirectionalLightData);
  253.     if ( myFillLight == nil )
  254.         goto bail;
  255.  
  256.     /*     Create light group and add each of the lights into the group. */
  257.     myLightList = Q3LightGroup_New();
  258.     if ( myLightList == nil )
  259.         goto bail;
  260.     myGroupPosition = Q3Group_AddObject(myLightList, myAmbientLight);
  261.     if ( myGroupPosition == 0 )
  262.         goto bail;
  263.     myGroupPosition = Q3Group_AddObject(myLightList, myPointLight);
  264.     if ( myGroupPosition == 0 )
  265.         goto bail;
  266.     myGroupPosition = Q3Group_AddObject(myLightList, myFillLight);
  267.     if ( myGroupPosition == 0 )
  268.         goto bail;
  269.  
  270.     Q3Object_Dispose( myAmbientLight ) ;
  271.     Q3Object_Dispose( myPointLight ) ;
  272.     Q3Object_Dispose( myFillLight ) ;
  273.  
  274.     /*     Done! */
  275.     return ( myLightList );
  276.     
  277. bail:
  278.     /*     If any of the above failed, then return nothing! */
  279.     return ( nil );
  280. }
  281.  
  282.  
  283. static TQ3GroupPosition MyAddTransformedObjectToGroup( TQ3GroupObject theGroup, TQ3Object theObject, TQ3Vector3D *translation )
  284. {
  285.     TQ3TransformObject    transform;
  286.  
  287.     transform = Q3TranslateTransform_New(translation);
  288.     Q3Group_AddObject(theGroup, transform);    
  289.     Q3Object_Dispose(transform);
  290.     return Q3Group_AddObject(theGroup, theObject);    
  291. }
  292.  
  293. TQ3GroupObject MyNewModel()
  294. {
  295.     TQ3GroupObject            myGroup = NULL;
  296.     TQ3GeometryObject        myBox;
  297.     TQ3BoxData                myBoxData;
  298.     TQ3ShaderObject            myIlluminationShader ;
  299.     TQ3Vector3D                translation;
  300.     
  301.     if ((myGroup = Q3DisplayGroup_New()) != NULL ) {
  302.         
  303.         MyAddShaderToGroup( myGroup ) ;
  304.     
  305.         /*  Define a shading type for the group */
  306.         /*  and add the shader to the group */
  307.     
  308.         myIlluminationShader = Q3PhongIllumination_New();
  309.         Q3Group_AddObject(myGroup, myIlluminationShader);
  310.  
  311.         myBoxData.boxAttributeSet = nil;
  312.         myBoxData.faceAttributeSet = nil;
  313.         
  314.         /*  create the box itself */
  315.         Q3Point3D_Set(&myBoxData.origin, 0, 0, 0);
  316.         Q3Vector3D_Set(&myBoxData.orientation, 0, 1, 0);
  317.         Q3Vector3D_Set(&myBoxData.majorAxis, 0, 0, 1);    
  318.         Q3Vector3D_Set(&myBoxData.minorAxis, 1, 0, 0);    
  319.         myBox = Q3Box_New(&myBoxData);
  320.         
  321.         /*  put four copies of the box into the group, each one with its own translation */
  322.         translation.x = 0;translation.y = 0;translation.z = 0;
  323.         MyAddTransformedObjectToGroup( myGroup, myBox, &translation ) ;
  324.     }
  325.     
  326.     /*  dispose of the objects we created here */
  327.     if( myIlluminationShader ) 
  328.         Q3Object_Dispose(myIlluminationShader);    
  329.                 
  330.     if( myBox ) 
  331.         Q3Object_Dispose( myBox );
  332.     
  333.     /*     Done! */
  334.     return ( myGroup );
  335. }
  336.  
  337.  
  338.  
  339. /* ----------------------------------------------------------------------------------------------- */
  340.  
  341. static TQ3Status GetDocumentGroupBoundingBox( 
  342.     DocumentPtr theDocument , 
  343.     TQ3BoundingBox *viewBBox)
  344. {
  345.     TQ3Status        status;
  346.     TQ3ViewStatus    viewStatus ;
  347.     
  348.     status = Q3View_StartBoundingBox( theDocument->fView, kQ3ComputeBoundsApproximate );
  349.     do {
  350.         status = Document_SubmitScene( theDocument ) ;
  351.     } while((viewStatus = Q3View_EndBoundingBox( theDocument->fView, viewBBox )) == kQ3ViewStatusRetraverse );
  352.     return status ;
  353. }
  354.  
  355.  
  356. /* ---------------------------------------------------------------------------------- */
  357. void GetGroupBBox(
  358.     DocumentPtr            theDocument,
  359.     TQ3BoundingBox         *viewBBox)
  360. {
  361.     TQ3Point3D                     from     = { 0.0, 0.0, 1.0 };
  362.     TQ3Point3D                     to         = { 0.0, 0.0, 0.0 };
  363.     TQ3Vector3D                 up         = { 0.0, 1.0, 0.0 };
  364.     
  365.     float                         fieldOfView = .52359333333;
  366.     float                         hither         =  0.5;
  367.     float                         yon         =  1.5;
  368.     TQ3GroupObject                mainGroup = theDocument->fModel ;
  369.  
  370.     TQ3Status                    status;
  371.     
  372.     status = GetDocumentGroupBoundingBox( theDocument , viewBBox) ;
  373.                                         
  374.     /*  */
  375.     /*   If we have a point model, then the "viewBBox" would end up */
  376.     /*   being a "singularity" at the location of the point.  As */
  377.     /*   this bounding "box" is used in setting up the camera spec, */
  378.     /*   we get bogus input into Escher. */
  379.     
  380.     {
  381.          float        xSize, ySize, zSize;
  382.         
  383.         xSize = viewBBox->max.x - viewBBox->min.x;
  384.         ySize = viewBBox->max.y - viewBBox->min.y;
  385.         zSize = viewBBox->max.z - viewBBox->min.z;
  386.  
  387.         if (xSize <= kQ3RealZero &&
  388.             ySize <= kQ3RealZero &&
  389.             zSize <= kQ3RealZero) {
  390.             
  391.             viewBBox->max.x += 0.0001;
  392.             viewBBox->max.y += 0.0001;
  393.             viewBBox->max.z += 0.0001;
  394.             
  395.             viewBBox->min.x -= 0.0001;
  396.             viewBBox->min.y -= 0.0001;
  397.             viewBBox->min.z -= 0.0001;
  398.         }
  399.     }
  400. }
  401.  
  402.  
  403.  
  404.  
  405. /* ------------------------------------------------------------------------ */
  406.  
  407.  
  408. TQ3Point3D AdjustCamera(
  409.     DocumentPtr            theDocument)
  410. {
  411.     float                         fieldOfView;
  412.     float                         hither;
  413.     float                         yon;
  414.     TQ3CameraPlacement            placement;
  415.     TQ3CameraRange                range;
  416.     TQ3BoundingBox                 viewBBox;
  417.     long                         fromAxis;    
  418.     float                         maxDimension;
  419.      float                        xSize, ySize, zSize;
  420.     float                        weights[2] = { 0.5, 0.5 };
  421.     TQ3Point3D                    points[2];
  422.     TQ3Vector3D                     viewVector;
  423.     TQ3Vector3D                    normViewVector;
  424.     TQ3Vector3D                    eyeToFrontClip;
  425.     TQ3Vector3D                    eyeToBackClip;
  426.     float                        viewDistance;
  427.     TQ3Vector3D                    diagonalVector;
  428.     float                        ratio;
  429.     TQ3CameraObject                camera;
  430.     
  431.     TQ3ViewObject                theView = theDocument->fView ;
  432.     TQ3GroupObject                mainGroup = theDocument->fModel ;
  433.     
  434.     TQ3Point3D                    *documentGroupCenter = &theDocument->fGroupCenter ;
  435.     float                        *documentGroupScale  = &theDocument->fGroupScale ;
  436.  
  437.     short                        winWidth,
  438.                                 winHeight;
  439.                                 
  440.     winWidth = ((theDocument->fWindow)->portRect.right - (theDocument->fWindow)->portRect.left);
  441.     winHeight = ((theDocument->fWindow)->portRect.bottom - (theDocument->fWindow)->portRect.top);
  442.     
  443.     Q3View_GetCamera( theView, &camera);
  444.     GetGroupBBox( theDocument, &viewBBox);
  445.  
  446.     /*
  447.      *  If we have a point model, then the "viewBBox" would end up
  448.      *  being a "singularity" at the location of the point.  As
  449.      *  this bounding "box" is used in setting up the camera spec,
  450.      *  we get bogus input into Escher.
  451.      */
  452.     xSize = viewBBox.max.x - viewBBox.min.x;
  453.     ySize = viewBBox.max.y - viewBBox.min.y;
  454.     zSize = viewBBox.max.z - viewBBox.min.z;
  455.  
  456.     if (xSize <= kQ3RealZero &&
  457.         ySize <= kQ3RealZero &&
  458.         zSize <= kQ3RealZero)  {
  459.         viewBBox.max.x += 0.0001;
  460.         viewBBox.max.y += 0.0001;
  461.         viewBBox.max.z += 0.0001;
  462.         
  463.         viewBBox.min.x -= 0.0001;
  464.         viewBBox.min.y -= 0.0001;
  465.         viewBBox.min.z -= 0.0001;
  466.     }
  467.  
  468.     points[0] = viewBBox.min;
  469.     points[1] = viewBBox.max;
  470.  
  471.     Q3Point3D_AffineComb(points, weights, 2, documentGroupCenter);
  472.  
  473.     /*
  474.      *  The "from" point is on a vector perpendicular to the plane
  475.      *  in which the bounding box has greatest dimension.  As "up" is
  476.      *  always in the positive y direction, look at x and z directions.
  477.      */
  478.     xSize = viewBBox.max.x - viewBBox.min.x;
  479.     zSize = viewBBox.max.z - viewBBox.min.z;
  480.     
  481.     if (xSize > zSize) {
  482.         fromAxis = kQ3AxisZ;
  483.     } else {
  484.         fromAxis = kQ3AxisX;
  485.     }
  486.  
  487.     /*
  488.      *  Compute the length of the diagonal of the bounding box.
  489.      *
  490.      *  The hither and yon planes are adjusted so that the
  491.       *  diagonal of the bounding box is 7/8 the size of the
  492.       *  minimum dimension of the view frustum. The diagonal is used instead
  493.       *  of the maximum size (in x, y, or z) so that when you rotate
  494.       *  the object, the corners don't get clipped out.
  495.       */
  496.     Q3Point3D_Subtract(
  497.         &viewBBox.max,
  498.         &viewBBox.min,
  499.         &diagonalVector);
  500.  
  501.     maxDimension    =    Q3Vector3D_Length(&diagonalVector);
  502.     maxDimension    *=    8.0 / 7.0;
  503.     
  504.     ratio = 1.0 / maxDimension;
  505.             
  506.     *documentGroupScale = ratio;
  507.     
  508.     Q3Camera_GetPlacement(camera, &placement);
  509.  
  510.     Q3Point3D_Subtract(
  511.         &placement.cameraLocation,
  512.         &placement.pointOfInterest,
  513.         &viewVector);
  514.         
  515.     viewDistance = Q3Vector3D_Length(&viewVector);
  516.     
  517.     Q3Vector3D_Normalize(&viewVector, &normViewVector);
  518.     
  519.     Q3Vector3D_Scale(&normViewVector, 
  520.                      viewDistance - ratio * maxDimension/2.0,
  521.                      &eyeToFrontClip);
  522.                     
  523.     Q3Vector3D_Scale(&normViewVector, 
  524.                     viewDistance + ratio * maxDimension/2.0,
  525.                     &eyeToBackClip);
  526.  
  527.     hither     = Q3Vector3D_Length(&eyeToFrontClip);
  528.     yon     = Q3Vector3D_Length(&eyeToBackClip);
  529.     
  530.     fieldOfView = 2 * atan((ratio * maxDimension/2.0)/hither);
  531.  
  532.     range.hither                 = hither;
  533.     range.yon                     = yon;
  534.  
  535.     Q3Camera_SetRange(camera, &range);
  536.  
  537.     Q3ViewAngleAspectCamera_SetFOV(
  538.         camera, fieldOfView);
  539.  
  540.     Q3ViewAngleAspectCamera_SetAspectRatio(
  541.         camera, (float) winWidth / (float) winHeight);
  542.  
  543.     Q3Object_Dispose(camera);
  544.     
  545.     return( *documentGroupCenter );
  546. }
  547.  
  548.